﻿using mozhi.smarterp.Finance.Accounts.Repository;
using mozhi.smarterp.Finance.Basedatas.Events;
using mozhi.smarterp.Finance.Basedatas.ThirdParties;
using mozhi.smarterp.Finance.Enums;
using mozhi.smarterp.Finance.Querys;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;

namespace mozhi.smarterp.Finance.Basedatas
{
    public class ThirdPartyAppService : BaseDataAppService<ThirdParty, ThirdPartyDto, ThirdPartyCreateDto, ThirdPartyUpdateDto>, IThirdPartyAppService
    {
        private IAccountRepository _accountRepository;
        public ThirdPartyAppService(IAccountRepository accountRepository, IServiceProvider serviceProvider)
            : base(serviceProvider, ModuleCodeType.Thirdparty)
        {
            _accountRepository = accountRepository;
        }


        public override async Task<PagedResultDto<ThirdPartyDto>> FindAsync(PageQuery query)
        {
            var result = await base.FindAsync(query);

            var thirdParties = result.Items.ToList();

            if (thirdParties == null || thirdParties.Count == 0)
                return result;

            await LoadAccountInfoAsync(thirdParties);

            return result;

        }

        public override async Task<ThirdPartyDto> CreateAsync(ThirdPartyCreateDto dto)
        {
            await Validate(null, dto.Code, dto.Name);
            await ValidateAccount(dto.CurrentAccountId);

            var thirdParty = new ThirdParty(_guidGenerator.Create(), dto.Code, dto.Name, dto.CurrentAccountId);

            thirdParty = await _repository.InsertAsync(thirdParty);

            var result = ObjectMapper.Map<ThirdParty, ThirdPartyDto>(thirdParty);

            await LoadAccountInfoAsync(new List<ThirdPartyDto> { result });

            await _operationLogManager.LogAsync(ModuleCodeType.Thirdparty, Enums.OperationType.Add, thirdParty, null);

            return result;
        }

        public override async Task<ThirdPartyDto> UpdateAsync(ThirdPartyUpdateDto dto)
        {
            var thirdParty = await _repository.GetAsync(dto.Id);

            if (thirdParty == null)
                throw new UserFriendlyException("第三方不存在", "100000");

            var oldThirdParty = ObjectMapper.Map<ThirdParty, ThirdPartyDto>(thirdParty);

            await Validate(dto.Id, dto.Code, dto.Name);

            await ValidateAccount(dto.CurrentAccountId);

            thirdParty.Change(dto.Code, dto.Name, dto.Activated);
            thirdParty.ChangeAccount(dto.CurrentAccountId);

            thirdParty = await _repository.UpdateAsync(thirdParty);

            var result = ObjectMapper.Map<ThirdParty, ThirdPartyDto>(thirdParty);

            await LoadAccountInfoAsync(new List<ThirdPartyDto>() { result });

            await _operationLogManager.LogAsync(ModuleCodeType.Thirdparty, Enums.OperationType.Update, oldThirdParty, result);

            return result;
        }

        public override async Task<ThirdPartyDto> DeleteAsync(Guid id)
        {
            var thirdParty = await base.DeleteAsync(id);

            await _distributedEventBus.PublishAsync(new DataAssociationRemoveEvent(id, thirdParty.CurrentAccountId));

            return thirdParty;
        }

        #region
        private async Task LoadAccountInfoAsync(List<ThirdPartyDto> thirdParties)
        {
            var accountIds = thirdParties.Where(x => x.CurrentAccountId != default).Select(x => x.CurrentAccountId).Distinct().ToList();

            if (accountIds.Count == 0)
                return;

            var accounts = await _accountRepository.FindAsync(new AccountQuery() { Ids = accountIds });


            foreach (var thirdParty in thirdParties)
            {
                thirdParty.CurrentAccountName = accounts.FirstOrDefault(x => x.Id == thirdParty.CurrentAccountId)?.FullName;
            }
        }


        private async Task ValidateAccount(Guid currentAccountId)
        {
            var accounts = await _accountRepository.FindAsync(new AccountQuery() { Ids = new List<Guid> { currentAccountId } });

            var matchCurrentAccount = accounts.FirstOrDefault(x => x.Id == currentAccountId);

            if (matchCurrentAccount == null)
                throw new UserFriendlyException("往来科目不存在", "100000");

            if (!matchCurrentAccount.Activated)
                throw new UserFriendlyException("往来科目已禁用", "100000");

            if (!matchCurrentAccount.IsLeaf)
                throw new UserFriendlyException("往来科目不是最子级科目", "100000");


        }

        #endregion
    }
}
